package org.study.waitnotify;

import java.util.concurrent.TimeUnit;

/**
 * https://blog.csdn.net/qq_40550018/article/details/87859399
 *
 * @author Administrator
 * @date 2021-08-19
 */
public class WaitNotifyTest implements Runnable {
    public static void main(String[] args) throws InterruptedException {
        WaitNotifyTest testWait = new WaitNotifyTest();
        Thread thread = new Thread(testWait);
        thread.start();
        TimeUnit.SECONDS.sleep(1);
        testWait.setFlag(false);
        Thread thread1 = new Thread(testWait);
        thread1.start();
    }

    private final Object object = new Object();
    private boolean flag = true;

    public boolean isFlag() {
        return flag;
    }

    public void setFlag(boolean flag) {
        this.flag = flag;
    }

    @Override
    public void run() {
        if (flag) {
            synchronized (object) {
                try {
                    System.out.println("线程开始执行。。。");
                    TimeUnit.SECONDS.sleep(1);
                    // 1、wait()是Object里面的方法，而不是Thread里面的，这一点很容易搞错。它的作用是将当前线程置于预执行队列，并在wait()所在的代码处停止，等待唤醒通知。
                    // 2、wait()只能在同步代码块或者同步方法中执行，如果调用wait()方法，而没有持有适当的锁，就会抛出异常。
                    // 3、wait()方法调用后悔释放出锁，线程与其他线程竞争重新获取锁。
                    object.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("线程执行结束。。。");
            }
        } else {
            synchronized (object) {
                try {
                    TimeUnit.SECONDS.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                // 1、notify()方法也是要在同步代码块或者同步方法中调用的，它的作用是使停止的线程继续执行，调用notify()方法后，会通知那些等待当前线程对象锁的线程，并使它们重新获取该线程的对象锁，如果等待线程比较多的时候，则有线程规划器随机挑选出一个呈wait状态的线程。
                // 2、notify()调用之后不会立即释放锁，而是当执行notify()的线程执行完成，即退出同步代码块或同步方法时，才会释放对象锁。
                object.notify();
            }
        }
    }
}
